package cn.chenyumeng.blog.service.admin.impl;

import cn.chenyumeng.blog.dto.BlogDTO;
import cn.chenyumeng.blog.entity.Blog;
import cn.chenyumeng.blog.entity.BlogTag;
import cn.chenyumeng.blog.exception.CustomException;
import cn.chenyumeng.blog.mapper.BlogMapper;
import cn.chenyumeng.blog.mapper.BlogTagMapper;
import cn.chenyumeng.blog.service.admin.BlogService;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.Instant;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

/**
 * @program: blog->BlogServiceImpl
 * @description:
 * @author: cg
 * @create: 2020-07-26 23:14
 **/
@Service
public class BlogServiceImpl implements BlogService {

    @Autowired
    private BlogMapper blogMapper;

    @Autowired
    private BlogTagMapper blogTagMapper;

    /**
     * 观看量自增
     *
     * @param id
     */
    @Transactional
    @Override
    public boolean increaseViews(Long id) {
        Blog blog = blogMapper.queryById(id);
        if (blog == null) {
            return false;
        }
        blog.setViews(blog.getViews() + 1);
        return blogMapper.update(blog) != 0;
    }

    /**
     * 通过ID查询单条数据
     *
     * @param id 主键
     * @return 实例对象
     */
    @Transactional
    @Override
    public BlogDTO queryById(Long id) {
        Blog blog = blogMapper.queryById(id);
        if (blog == null) {
            return null;
        }
        BlogDTO blogDTO = new BlogDTO();
        BeanUtils.copyProperties(blog, blogDTO);
        blogDTO.setTagIds(getTagIds(blogDTO.getId()));
        return blogDTO;
    }

    /**
     * 查询多条数据
     *
     * @param page 页数
     * @param size 大小
     * @return 对象列表
     */
    @Transactional
    @Override
    public PageInfo<BlogDTO> queryAllByLimit(int page, int size) {
        PageHelper.startPage(page, size);
        List<Blog> blogs = blogMapper.queryAllExcludeDescription();
        if (blogs.isEmpty()) {
            return null;
        }
        PageInfo blogPageInfo = new PageInfo(blogs);
        List<BlogDTO> dtoList = new ArrayList<>();
        blogPageInfo.getList().forEach(blog -> {
            BlogDTO blogDTO = new BlogDTO();
            BeanUtils.copyProperties(blog, blogDTO);
            blogDTO.setTagIds(getTagIds(blogDTO.getId()));
            dtoList.add(blogDTO);
        });
        blogPageInfo.setList(dtoList);
        return blogPageInfo;
    }

    /**
     * 通过条件查询多条数据
     *
     * @param page    页数
     * @param size    大小
     * @param blogDTO 实体条件
     * @return 对象列表
     */
    @Transactional
    @Override
    public PageInfo<BlogDTO> queryAllByBlog(int page, int size, BlogDTO blogDTO) {
        List<Blog> blogs = null;
        List<BlogDTO> dtoList = new ArrayList<>();
        PageInfo blogPageInfo = null;
        // 查询条件带有tagIds
        if (blogDTO.getTagIds() != null) {
            Blog blog = new Blog();
            BeanUtils.copyProperties(blogDTO, blog);
            List<Long> blogIds = getBlogIds(blogDTO.getTagIds());
            PageHelper.startPage(page, size);
            blogs = blogMapper.queryAllByBlog(blog, blogIds);
            if (blogs.isEmpty()) {
                return null;
            }
            blogPageInfo = new PageInfo(blogs);
            blogPageInfo.getList().forEach(blogInfo -> {
                BlogDTO dto = new BlogDTO();
                BeanUtils.copyProperties(blogInfo, dto);
                dto.setTagIds(getTagIds(dto.getId()));
                dtoList.add(dto);
            });
            blogPageInfo.setList(dtoList);
            //  查询条件没有tagIds
        } else {
            Blog blog = new Blog();
            BeanUtils.copyProperties(blogDTO, blog);
            PageHelper.startPage(page, size);
            blogs = blogMapper.queryAllByBlog(blog, null);
            if (blogs.isEmpty()) {
                return null;
            }
            blogPageInfo = new PageInfo(blogs);
            blogPageInfo.getList().forEach(blog1 -> {
                BlogDTO dto = new BlogDTO();
                BeanUtils.copyProperties(blog1, dto);
                dto.setTagIds(getTagIds(dto.getId()));
                dtoList.add(dto);
            });
            blogPageInfo.setList(dtoList);
        }
        return blogPageInfo;
    }

    /**
     * 通过tagIds查询所对应的blogIds
     *
     * @param tagIds
     * @return
     */
    private List<Long> getBlogIds(List<Long> tagIds) {
        // 用来存储标签Id集所对应的博客Id集
        List<Long> blogIds = new ArrayList<>();
        // 通过标签id集获取对应的博客标签集
        List<BlogTag> blogTags = blogTagMapper.selectBlogTagsByTagIds(tagIds);
        // 循环将博客标签集的每个博客id存入博客Id集
        blogTags.forEach(blogTag -> blogIds.add(blogTag.getBlogId()));
        return blogIds;
    }

    /**
     * 通过blogId查询所对应的tagIds
     *
     * @param blogId
     * @return
     */
    private List<Long> getTagIds(Long blogId) {
        List<BlogTag> blogTags = blogTagMapper.selectBlogTagsByBlogId(blogId);
        List<Long> tags = new ArrayList<>();
        blogTags.forEach(blogTag -> tags.add(blogTag.getTagId()));
        return tags;
    }

    /**
     * 新增数据
     *
     * @param blogDTO 实例对象
     * @return 实例对象
     */
    @Transactional
    @Override
    public BlogDTO insert(BlogDTO blogDTO) {
        blogDTO.setCreateTime(Date.from(Instant.now()));
        blogDTO.setUpdateTime(Date.from(Instant.now()));
        blogDTO.setViews(0);
        Blog blog = new Blog();
        BeanUtils.copyProperties(blogDTO, blog);
        int insertCount = blogMapper.insert(blog);
        if (insertCount <= 0) {
            return null;
        }
        BeanUtils.copyProperties(blog, blogDTO);
        // 中间表插入数据
        ArrayList<BlogTag> blogTagList = new ArrayList<>();
        for (Long tagId : blogDTO.getTagIds()) {
            BlogTag blogTag = new BlogTag();
            blogTag.setBlogId(blogDTO.getId());
            blogTag.setTagId(tagId);
            blogTagList.add(blogTag);
        }
        int batchBlogTagCount = blogTagMapper.batchBlogTag(blogTagList);
        if (batchBlogTagCount <= 0) {
            throw new CustomException("数据库插入异常");
        }
        return blogDTO;
    }

    /**
     * 修改数据
     *
     * @param blogDTO 实例对象
     * @return 实例对象
     */
    @Transactional
    @Override
    public BlogDTO update(BlogDTO blogDTO) {
        blogDTO.setUpdateTime(Date.from(Instant.now()));
        Blog blog = new Blog();
        BeanUtils.copyProperties(blogDTO, blog);
        int updateCount = blogMapper.update(blog);
        if (updateCount <= 0) {
            return null;
        }
        // 删除博客和标签关联
        int deleteCount = blogTagMapper.deleteBlogTagByBlogId(blogDTO.getId());
        if (deleteCount <= 0) {
            return null;
        }
        // 重新插入
        ArrayList<BlogTag> blogTagList = new ArrayList<>();
        for (Long tagId : blogDTO.getTagIds()) {
            BlogTag blogTag = new BlogTag();
            blogTag.setBlogId(blogDTO.getId());
            blogTag.setTagId(tagId);
            blogTagList.add(blogTag);
        }
        int batchBlogTagCount = blogTagMapper.batchBlogTag(blogTagList);
        if (batchBlogTagCount <= 0) {
            throw new CustomException("数据库插入异常");
        }
        BlogDTO target = new BlogDTO();
        BeanUtils.copyProperties(blogMapper.queryAllByBlog(new Blog(blogDTO.getId()), null).get(0), target);
        return target;
    }

    /**
     * 通过主键删除数据
     *
     * @param id 主键
     * @return 是否成功
     */
    @Transactional
    @Override
    public boolean deleteById(Long id) {
        int i = blogTagMapper.deleteBlogTagByBlogId(id);
        if (i <= 0) {
            return false;
        }
        return blogMapper.deleteById(id) > 0;
    }

}
